//! trait关键字
//!  trait里面的函数可以没有函数体，实现代码交给具体实现它的类型去补充：
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;

trait HasArea {
    fn area(&self) -> f64;
}
//trait 继承
trait CircleArea: HasArea {
    fn circle_area(&self) -> f64;
}

struct Circle {
    x: f64,
    y: f64,
    radius: f64,
}
impl HasArea for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

impl CircleArea for Circle {
    fn circle_area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

#[test]
pub fn trait_demo1(){
    let c = Circle{
        x: 0.0_f64,
        y: 0.0_f64,
        radius: 1.0_f64,
    };
    println!("{}", c.area());
}


/* trait 类似接口*/
pub trait Summary {
    //方法，没有实现
    fn summarize(&self) -> String;
    //默认实现
    fn show(&self) {
        println!("默认实现");
    }
}

//结构体
pub struct NewsArticle {
    headline: String,
    location: String,
    author: String,
}
//为结构体定义方法同时实现Summary这个trait
impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{} by {}({})", self.headline, self.author, self.location)
    }
}
//再实现Display这个trait
impl Display for NewsArticle {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(
            f,
            "headline:{}, location:{}, author:{}",
            self.headline, self.location, self.author
        )
    }
}

//trait作为参数,&SomeTrait 类型和普通的指针类型&i32不同。它不仅包括指向真实对象的指针，还包括一个指向虚函数表的指针
fn notify(item: &(impl Summary + Display)) {
    println!("{}", item.summarize());
}
//第二种写法
fn notify2<T: Summary + Display>(item: &T) {
    println!("{}", item.summarize());
}
//第三种写法
fn notify3<T>(item: &T)
    where
        T: Summary + Display, //多个泛型后面继续写
{
    println!("{}", item);
}

//trait作为返回值类型
fn notify4(s: &str) -> impl Summary + Display {
    //只能返回固定的类型，返回可能不同的类型会报错
    NewsArticle {
        headline: String::from("hello world"),
        location: String::from("中国"),
        author: String::from("李四"),
    }
}

#[test]
pub fn trait_demo2() {
    let article = NewsArticle {
        headline: "hello".to_string(),
        location: "四川".to_string(),
        author: "张三".to_string(),
    };
    let s = article.summarize();
    println!("{}", article); //实现了Display可以直接打印
    println!("{}", s);

    notify(&article);
    notify2(&article);
    notify3(&article);
}

// trait继承

trait Foo {
    fn foo(&self);
}

trait FooBar : Foo {
    fn foobar(&self);
}

struct Baz;

impl Foo for Baz {
    fn foo(&self) { println!("foo"); }
}

impl FooBar for Baz {
    fn foobar(&self) { println!("foobar"); }
}

//derive属性
//Rust提供了一个属性derive来自动实现一些trait，这样可以避免重复繁琐地实现他们，能被derive使用的trait包括：Clone,
// Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd
#[derive(Debug)]
struct Foo2;